/* -*-C-*-
********************************************************************************
*
* File:         wtin.c
* RCS:          $Id: wtin.c,v 1.11 1995/06/26 21:06:00 jay Exp $
* Description:  WINTERP main() file.
* Author:       Chris Guthrie, Niels Mayer
* Created:      1995
* Modified:     Tue Jun 27 13:52:11 1995 (Niels Mayer) npm@indeed
* Language:     C
* Package:      N/A
* Status:       Experimental, do not distribute.
*
* Copyright (C) 1995, Enterprise Integration Technologies Corp.
*
********************************************************************************
*/

#include <stdio.h>
#include <ctype.h>
#include "atom.h"
#include "dtd.h"
#include "html.h"

FILE *error = stderr;

static void WTINstroke(Block *bp);
static void output_potential_multiline_text_node(char *nname,
						 Block *top,
						 int depth);
static void dump_tree(Block *top, int depth);
static int _WTINHTMLError(struct error *errp);

main(int ac, char *argv[])
{
    Block *bp;
    extern FILE *yyin;

    if (ac > 1) {
	yyin = fopen(argv[1], "r");
	if (yyin == NULL) {
	    perror(argv[1]);
	    exit (1);
	}
    }
    if (ac > 2) {
	error = fopen(argv[2], "w");
	if (error == NULL) {
	    perror(argv[2]);
	    exit (2);
	}
    }
    HTMLSetErrorHand(_WTINHTMLError);
    HTMLParseBegin();
    HTMLParseDo(yyin);
    bp = HTMLParseEnd();
    WTINstroke(bp);
    dump_tree(bp, 0);
    exit(0);
}

static char temptext[BUFSIZ];

/* (char *nname, 
    struct block *top,
    int depth) */

static void
output_potential_multiline_text_node(char *nname, Block *top, int depth)
{
  char *src, *dest;
  int idx;

  src = &((top->data)[0]);
  dest = &(temptext[0]);
  idx = 0;
  while (*src) {
    if (idx >= (BUFSIZ - 2)) {
      idx = 0;
      *dest = '\000';
      fprintf(stdout, " %d %d\n%s\n%s \n",
	      depth, HTMLGetBFlags(top), nname,
	      temptext);
      dest = &(temptext[0]);
    }
    else {
      switch (*src) {
      case '\n':
	/*
	 * NPM: need to handle case of text containing newline, since
	 * updated WINTERP reader expects TEXT w/o embedded newlines.
	 * In this case, use multiple <nname> blocks at same level to
	 * denote multiple lines.  Only a problem in PRE ...
	 */
	src++;
	*dest = '\000';
	idx = 0;
	/*
	 * NPM: print out a <nname> node, terminate with '\r' -- on winterp
	 * side, we check for lines with this ending character (without
	 * going through string char-by-char) and replace them back with
	 * '\n'.
	 */
	fprintf(stdout, " %d %d\n%s\n%s\r\n",
		depth, HTMLGetBFlags(top), nname,
		temptext);
	dest = &(temptext[0]);
	break;
      default:
	*dest++ = *src++;
	idx++;
	break;
      }
    }
  }
  if (dest != &(temptext[0])) {
    *dest = '\000';
    fprintf(stdout, " %d %d\n%s\n%s \n",
	    depth, HTMLGetBFlags(top), nname,
	    temptext);
  }
}

static void
dump_tree(Block *top, int depth)
{
  Block *cur;

  /* Print out block data */
  if (depth != 0) { 		/* Ignore top block data */
    switch (top->type) {
    case DOCTYPE:
      fprintf(stdout, " %d %d\n!DOCTYPE\n%s \n",
	      depth, HTMLGetBFlags(top),
	      top->data);
      break;
    case CMNT:
      output_potential_multiline_text_node("!--", top, depth);
      break;
    case PCDATA:
      output_potential_multiline_text_node("TEXT", top, depth);
      break;
    case TAG:
#if 0
      if (top->bAtom == GetAtom("UNKNOWN")) {
	/* NPM: for consistency w/ other markups, upcase unknown markup */
	char *src, *dest;
	src = &((top->data)[0]);
	dest = &(temptext[0]);
	while (*src)
	  *dest++ = toupper(*src++);
	*dest = '\000';
	fprintf(stdout, " %d 0\n%s\n", depth, temptext);
      }
      else
#endif
      if (top->bAtom == GetAtom("TITLE")) {
	/*
	 * NPM: the title text is "under" the title node, remove that node
	 * from the parse tree and make it the data for the title node
	 */
	cur = top->children;
	if (cur) {
	  if (cur->type == PCDATA) {
	    top->data = cur->data;
	    if (cur->next_sib)
	      fprintf(stderr, "Internal error in HTML parser dump_tree()\n\t-- TITLE's TEXT child has non-NULL '->next_sib' slot...\n");
	  }
	  /*
	   * NPM: now that the TITLE node contains the title text from
	   * the TEXT child, get rid of the children nodes under TITLE
	   * so that they don't get printed during recursive call to
	   * dump_tree() below
	   */
	  top->children = NULL;	/* NPM: note that this is a memory leak of the TITLE children nodes... */
	  /*
	   * NPM: ensure that there are no attributes in title since
	   * we're printing the TEXT of the TITLE where the attributes
	   * would be. Ensure that "print out any attributes" below doesn't
	   * happen.
	   */
	  top->attrs = NULL;
	}

	/*
	 * NPM: ensure that the TITLE string is shorter than BUFSIZ-1
	 * characters. winterp input routines expect lines shorter
	 * than this length. For this TITLE case, just truncate the
	 * title string...
	 */
	if (strlen(top->data) >= (BUFSIZ - 1))
	  (top->data)[(BUFSIZ - 1)] = '\000';

	/*
	 * NPM: print out the TITLE markup and the value of the TITLE,
	 * but leave off the trailing " \n" that we'd normally print
	 * after a TEXT node because that is done by the final printf()
	 * after "print out any attributes" below. Setting 
	 * "top->attrs = NULL" above ensures that nothing gets printed in
	 * "print out any attributes" routine.
	 */
	fprintf(stdout, " %d %d\nTITLE\n%s",
		depth, HTMLGetBFlags(top),
		top->data);
      }
      else {
	fprintf(stdout, " %d %d\n%s\n",
		depth, HTMLGetBFlags(top),
		GetAtomVal(top->bAtom));
      }

      /* print out any attributes */
      if (top->attrs) {
	struct attribute *ap = top->attrs;
	while (ap) {
	  /* Need to massage double quotes */
	  fprintf(stdout, " %s", ap->name);
	  if (ap->data) {
	    if (ap->flags & DQUOTEDVALUE)
	      fprintf(stdout, "=\"%s\"", ap->data);
	    else if (ap->flags & SQUOTEDVALUE)
	      fprintf(stdout, "='%s'", ap->data);
	    else
	      fprintf(stdout, "=%s", ap->data);
	  }
	  ap = ap->next;
	}
      }
      fprintf(stdout, " \n");
      break;
    default:
      fprintf(stderr, "Internal error in HTML parser dump_tree()\n\t-- unknown value for top->type\n");
      break;
    }
  }
  /* Print out children */
  cur = top->children;
  while (cur) {
    dump_tree(cur, depth + 1);
    cur = cur->next_sib;
  }
}

static int
_WTINHTMLError(struct error *errp)
{
    char *type;

    if (errp->severity > E_WARNING)
	type = "Error";
    else
	type = "Warning";

    fprintf(error,
	    "%s: %d: %s\n",
	    type,
	    errp->lineno,
	    errp->message);

    return (1);
}

/*
 * The parser returns a very strict parse tree.
 * This function fixes up some allowable problems.
 * Currently, it just fixes the case where <A NAME="#foo"> is
 * not correctly terminated with a </A>.  In this case, it
 * moves the child of the <A> up to be a sibling.
 */
static void
WTINstroke(Block *bp)
{
    Block *oldsib, *tmp;

    if (HTMLGetBType(bp) == TAG) {
	if (HTMLGetBAtom(bp) == GetAtom("A")) {
	    if (HTMLGetAttr(bp, "HREF") == 0) {
		/* fprintf(stderr, "Fixing bad <A>\n"); */
		if (HTMLGetBChild(bp)) {
		    oldsib = HTMLGetBSib(bp);
		    HTMLSetBSib(bp, HTMLGetBChild(bp));
		    HTMLSetBChild(bp, 0);
		    if (oldsib) {
			tmp = HTMLGetBSib(bp);
			while (HTMLGetBSib(tmp))
			    tmp = HTMLGetBSib(tmp);
			HTMLSetBSib(tmp, oldsib);
		    }
		}
	    }
	}
    }
    if (HTMLGetBChild(bp))
	WTINstroke(HTMLGetBChild(bp));
    if (HTMLGetBSib(bp))
	WTINstroke(HTMLGetBSib(bp));
}
